#include "Spark/Utils/Logger.h"
#include "Spark/Net/Channel.h"
#include "Spark/Net/EventLoop.h"
#include <iostream>

Channel::Channel(EventLoop* loop, int fd)
    : loop_(loop), FD_(fd), status_(Status::kNew)
{
}

Channel::~Channel()
{
}

void Channel::setCallback(CBType t, EventCallback cb)
{
    switch (t)
    {
        case CBType::READ:
            readEventCallback_ = std::move(cb);
            break;
        case CBType::WRITE:
            writeEventCallback_ = std::move(cb);
            break;
        case CBType::CLOSE:
            closeEventCallback_ = std::move(cb);
            break;
        case CBType::ERROR:
            errorEventCallback_ = std::move(cb);
            break;
        case CBType::EVENT:
            allEventCallback_ = std::move(cb);
            break;
        default:
            throw std::invalid_argument("invalid CBType");
    }
}

void Channel::disableAll()
{
    eventMask_ = static_cast<int>(Event::kNonEvent);
    update();
}

void Channel::remove()
{
    loop_->removeChannel(this);
}

void Channel::addReadEvent()
{
    eventMask_ |= Event::kReadEvent;
    update();
}

void Channel::addWriteEvent()
{
    eventMask_ |= Event::kWriteEvent;
    update();
}

void Channel::removeReadEvent()
{
    eventMask_ &= ~Event::kReadEvent;
    update();
}

void Channel::removeWriteEvent()
{
    eventMask_ &= ~Event::kWriteEvent;
    update();
}

bool Channel::isReadEvent() const
{
    return eventMask_ & Event::kReadEvent;
}

bool Channel::isWriteEvent() const
{
    return eventMask_ & Event::kWriteEvent;
}

bool Channel::isNonEvent() const
{
    return eventMask_ == static_cast<int>(Event::kNonEvent);
}

void Channel::updateEventMask(int eventMask)
{
    eventMask_ |= eventMask_;
    update();
}

void Channel::tieCallbackOwner(const std::shared_ptr<void>& cbOwner)
{
    weakTie_ = cbOwner;
    tied_ = true;
}

void Channel::update()
{
    loop_->updateChannel(this);
}

void Channel::handleEvent()
{
    std::shared_ptr<void> guard;
    if (tied_)
    {
        guard = weakTie_.lock();
        if (guard)
        {
            handleEventWithGuard();
        }
    }
    else
    {
        handleEventWithGuard();
    }
}

void Channel::handleEventWithGuard()
{
    if (allEventCallback_)
        allEventCallback_();

    if ((occurred_ & POLLHUP) && !(occurred_ & POLLIN))
    {
        if (closeEventCallback_)
            closeEventCallback_();
    }

    if (occurred_ & POLLNVAL)
    {
        LOG_ERROR << "fd[" << FD_ << "] POLLNVAL";
    }

    if (occurred_ & (POLLERR))
    {
        LOG_ERROR << "fd[" << FD_ << "] POLLERR";
        if (errorEventCallback_)
            errorEventCallback_();
    }

    if (occurred_ & (POLLIN | POLLPRI | POLLRDHUP))
    {
        if (readEventCallback_)
            readEventCallback_();
    }

    if (occurred_ & POLLOUT)
    {
        if (writeEventCallback_)
            writeEventCallback_();
    }
}